iT邦幫忙

2022 iThome 鐵人賽

DAY 10
0

今日目標,實現註冊功能。

註冊功能

UserRepository

  1. 在 user package 底下建立 java interface,名稱為 UserRepository,並將其檔案內容替換為:
    package com.example.user;
    
    import org.springframework.data.repository.CrudRepository;
    import org.springframework.stereotype.Repository;
    
    @Repository
    public interface UserRepository extends CrudRepository<UserModel, Integer> {
        UserModel findByEmail(String email);
        UserModel findByUsername(String username);
    }
    
    • @Repository:用於聲明這個 class 或 interface 可以用來執行資料庫的相關操作,並支援自動處理資料庫操作的異常
    • CrudRepository:已經寫好的 interface,可以在資料庫進行 CRUD 操作,後方的類型先後分別為「資料表的類、主鍵的類」,此處的資料表為 UserModel,而其主鍵 Id 為 Integer
    • 我們可以透過簡單 key word 來建立自定義查詢,比如 findByEmail,而這是 Spring Data JPA 所實現的,其依賴(spring-boot-starter-data-jpa)上次就已經被我們加入,所以此處就不再提一次,更多語法規則可以參考Spring Data JPA - Reference Documentation
  2. 在 CardsApplication 添加 @EnableJpaRepositories 用來掃描 JPA Repository,檔案完整內容為:
    package com.example.cards;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.autoconfigure.domain.EntityScan;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
    
    @SpringBootApplication
    @ComponentScan({
            "com.example",
    })
    @EnableJpaRepositories({
            "com.example",
    })
    @EntityScan({
            "com.example",
    })
    public class CardsApplication {
        public static void main(String[] args) {
            SpringApplication.run(CardsApplication.class, args);
        }
    }
    

UserService

  1. 在 user package 底下建立 java class,名稱為 UserService,並將其檔案內容替換為:
    package com.example.user;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    @Service
    public class UserService {
        @Autowired
        private UserRepository userRepository;
    
        public Integer addUser(UserModel user) {
            UserModel newUser = userRepository.save(user);
            return newUser.getId();
        }
    }
    
    • @Service:用於聲明其為 service,並由 Spring Boot 負責管理
    • @Autowired:會自動根據所要注入對象的類型,將其自動配對並注入,產生一個實例(instance),更詳細的在下方「注入」解說
  2. 這邊不需要特別去 CardsApplication 添加 scan 是因為先前 @ComponentScan 就包含了 service

修改 register.html

  1. 添加 th:object 與 th:filed 去綁定 form 的資料,用以傳回 controller
  2. register.hmlt 完整檔案內容為:
    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1 th:text="${name}"></h1>
        <form method="post" action="/register" th:object="${user}">
            <input type="email" id="email" name="email" placeholder="Email" th:field="*{email}" />
            <input type="text" id="username" name="username" placeholder="Username" th:field="*{username}" />
            <input type="password" id="password" name="password" placeholder="Password" th:field="*{password}" />
            <button type="submit">註冊</button>
        </form>
    </body>
    </html>
    

UserController

  1. 修改 UserController,注入 service,並建立 post mapping,完整檔案內容為:
    package com.example.user;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    
    @Controller
    public class UserController {
        @Autowired
        private UserService userService;
    
        @GetMapping("/register")
        public String viewRegisterPage(Model model) {
            model.addAttribute("name", "註冊");
            model.addAttribute("user", new UserModel());
            return "register";
        }
    
        @PostMapping("/register")
        public String registerProcess(UserModel user) {
            userService.addUser(user);
            return "redirect:/";
        }
    }
    
    • viewRegisterPage 的 model.addAttribute("user", new UserModel()):這是因為前端模板還是需要一個變數名稱為 user 的資料做傳遞,否則會報錯,所以給他一個空的 user 物件
    • @PostMapping("/register"):類似 @GetMapping,只差在這是 post 請求
    • registerProcess(UserModel user):參數的部分可以直接放我們期望接收到的類型,會將這邊的資料(也就是我們在 register.html 用 th:filed 所綁定的),自動解析成我們要求的類型
    • return "redirect:/":重新導向頁面,使用 redirect 關鍵字,搭配絕對路徑,這邊表示會回到根路徑

Demo Time

  1. 直接到 http://localhost:8080/register 頁面註冊吧,成功後應會跳回 hello 的頁面,因為我們設定回到 /
  2. 去資料庫看看有沒有剛剛自己新增的資料吧~~

注入(Autowired)與實例(Instance)

要來這次教學的重點之一了~~

  • 實例(instance),是指用 @Component@Service@Repository... 等註解所聲明的類別,這些類別受到 spring boot 管理,他們只會在這次運行時生成一次,並在後續用注入(autowired)的方式來使用,也因為在本次運行時只會執行一次,所以也可以作為不同 controller 之間共享的資料
  • 注入(autowired),其實有實例的概念後,注入就只是把實例拿來運用而已,在每次要使用這些實例前,都用 @Autowired 聲明即可,但要注意每一個實例都要宣告一次,這是新手常犯的錯誤

如果你剛自己亂玩了一下註冊功能,應該會發現幾個小問題,

  1. 填入長度完全沒限制
  2. username、email 居然可以重複
  3. 密碼並沒有受到保護,而是以明文存著

這些問題將在明天的文章做改善,明天就會說明如何在 Entity 添加限制(constraint),並自定義 unique 的註解聲明~~/images/emoticon/emoticon06.gif


上一篇
Day 08 - 註冊頁面
下一篇
Day 10 - Entity Constraints
系列文
Spring Boot... 深不可測31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言